#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <psp2/system_param.h>
#include <psp2/ctrl.h>

#include "ctrl_pad.h"
#include "init.h"

#define N_CTRL_REPORTS 4
#define MAX_HOLD_COUNT 65535

void resetPad(CtrlPad *pad)
{
    memset(pad, 0, sizeof(CtrlPad));
}

void readPad(CtrlPad *pad)
{
    int port, i;
    SceCtrlData ctrl_data;

    memcpy(pad->old, pad->current, sizeof(CtrlData));
    memcpy(pad->old_hold_count, pad->current_hold_count, sizeof(CtrlCount));
    memset(pad->current, 0, sizeof(CtrlData));

    for (i = 0; i < N_CTRL_REPORTS; i++)
    {
        if (i > 0)
            port = i + 1;
        else
            port = 0;

        memset(&ctrl_data, 0, sizeof(SceCtrlData));
        int ret = sceCtrlPeekBufferPositiveExt2(port, &ctrl_data, 1);
        if (ret < 0)
            continue;

        // if (CHECK_EXIT_APP(data.buttons))
        // exitApp();

        if (ctrl_data.buttons & SCE_CTRL_UP)
            pad->current[PAD_UP] = 1;
        if (ctrl_data.buttons & SCE_CTRL_DOWN)
            pad->current[PAD_DOWN] = 1;
        if (ctrl_data.buttons & SCE_CTRL_LEFT)
            pad->current[PAD_LEFT] = 1;
        if (ctrl_data.buttons & SCE_CTRL_RIGHT)
            pad->current[PAD_RIGHT] = 1;
        if (ctrl_data.buttons & SCE_CTRL_TRIANGLE)
            pad->current[PAD_TRIANGLE] = 1;
        if (ctrl_data.buttons & SCE_CTRL_CIRCLE)
            pad->current[PAD_CIRCLE] = 1;
        if (ctrl_data.buttons & SCE_CTRL_CROSS)
            pad->current[PAD_CROSS] = 1;
        if (ctrl_data.buttons & SCE_CTRL_SQUARE)
            pad->current[PAD_SQUARE] = 1;
        if (ctrl_data.buttons & SCE_CTRL_L1)
            pad->current[PAD_L1] = 1;
        if (ctrl_data.buttons & SCE_CTRL_R1)
            pad->current[PAD_R1] = 1;
        if (ctrl_data.buttons & SCE_CTRL_L2)
            pad->current[PAD_L2] = 1;
        if (ctrl_data.buttons & SCE_CTRL_R2)
            pad->current[PAD_R2] = 1;
        if (ctrl_data.buttons & SCE_CTRL_L3)
            pad->current[PAD_L3] = 1;
        if (ctrl_data.buttons & SCE_CTRL_R3)
            pad->current[PAD_R3] = 1;
        if (ctrl_data.buttons & SCE_CTRL_START)
            pad->current[PAD_START] = 1;
        if (ctrl_data.buttons & SCE_CTRL_SELECT)
            pad->current[PAD_SELECT] = 1;
        if (ctrl_data.buttons & SCE_CTRL_PSBUTTON)
            pad->current[PAD_PSBUTTON] = 1;

        if (ctrl_data.lx < ANALOG_CENTER - ANALOG_THRESHOLD)
            pad->current[PAD_LEFT_ANALOG_LEFT] = 1;
        else if (ctrl_data.lx > ANALOG_CENTER + ANALOG_THRESHOLD)
            pad->current[PAD_LEFT_ANALOG_RIGHT] = 1;

        if (ctrl_data.ly < ANALOG_CENTER - ANALOG_THRESHOLD)
            pad->current[PAD_LEFT_ANALOG_UP] = 1;
        else if (ctrl_data.ly > ANALOG_CENTER + ANALOG_THRESHOLD)
            pad->current[PAD_LEFT_ANALOG_DOWN] = 1;

        if (ctrl_data.rx < ANALOG_CENTER - ANALOG_THRESHOLD)
            pad->current[PAD_RIGHT_ANALOG_LEFT] = 1;
        else if (ctrl_data.rx > ANALOG_CENTER + ANALOG_THRESHOLD)
            pad->current[PAD_RIGHT_ANALOG_RIGHT] = 1;

        if (ctrl_data.ry < ANALOG_CENTER - ANALOG_THRESHOLD)
            pad->current[PAD_RIGHT_ANALOG_UP] = 1;
        else if (ctrl_data.ry > ANALOG_CENTER + ANALOG_THRESHOLD)
            pad->current[PAD_RIGHT_ANALOG_DOWN] = 1;
    }

    for (i = 0; i < PAD_N_BUTTONS; i++)
    {
        pad->pressed[i] = pad->current[i] & ~pad->old[i];
        pad->released[i] = ~pad->current[i] & pad->old[i];

        pad->hold[i] = pad->pressed[i];
        pad->hold2[i] = pad->pressed[i];

        if (pad->current[i])
        {
            if (pad->current_hold_count[i] < MAX_HOLD_COUNT)
                pad->current_hold_count[i]++;

            if (pad->hold_count[i] >= 10)
            {
                pad->hold[i] = 1;
                pad->hold_count[i] = 6;
            }

            if (pad->hold2_count[i] >= 10)
            {
                pad->hold2[i] = 1;
                pad->hold2_count[i] = 10;
            }

            pad->hold_count[i]++;
            pad->hold2_count[i]++;
        }
        else
        {
            pad->current_hold_count[i] = 0;
            pad->hold_count[i] = 0;
            pad->hold2_count[i] = 0;
        }
    }

    if (enter_button == SCE_SYSTEM_PARAM_ENTER_BUTTON_CIRCLE)
    {
        pad->old[PAD_ENTER] = pad->old[PAD_CIRCLE];
        pad->current[PAD_ENTER] = pad->current[PAD_CIRCLE];
        pad->pressed[PAD_ENTER] = pad->pressed[PAD_CIRCLE];
        pad->released[PAD_ENTER] = pad->released[PAD_CIRCLE];
        pad->hold[PAD_ENTER] = pad->hold[PAD_CIRCLE];
        pad->hold2[PAD_ENTER] = pad->hold2[PAD_CIRCLE];

        pad->old[PAD_CANCEL] = pad->old[PAD_CROSS];
        pad->current[PAD_CANCEL] = pad->current[PAD_CROSS];
        pad->pressed[PAD_CANCEL] = pad->pressed[PAD_CROSS];
        pad->released[PAD_CANCEL] = pad->released[PAD_CROSS];
        pad->hold[PAD_CANCEL] = pad->hold[PAD_CROSS];
        pad->hold2[PAD_CANCEL] = pad->hold2[PAD_CROSS];
    }
    else
    {
        pad->old[PAD_ENTER] = pad->old[PAD_CROSS];
        pad->current[PAD_ENTER] = pad->current[PAD_CROSS];
        pad->pressed[PAD_ENTER] = pad->pressed[PAD_CROSS];
        pad->released[PAD_ENTER] = pad->released[PAD_CROSS];
        pad->hold[PAD_ENTER] = pad->hold[PAD_CROSS];
        pad->hold2[PAD_ENTER] = pad->hold2[PAD_CROSS];

        pad->old[PAD_CANCEL] = pad->old[PAD_CIRCLE];
        pad->current[PAD_CANCEL] = pad->current[PAD_CIRCLE];
        pad->pressed[PAD_CANCEL] = pad->pressed[PAD_CIRCLE];
        pad->released[PAD_CANCEL] = pad->released[PAD_CIRCLE];
        pad->hold[PAD_CANCEL] = pad->hold[PAD_CIRCLE];
        pad->hold2[PAD_CANCEL] = pad->hold2[PAD_CIRCLE];
    }
}
